<?php
/**
 *
 *
 * @author Ralph de Boom <php5-sidnepp@mijndomein.nl>
 * @author Peter Keizer <php5-sidnepp@mijndomein.nl>
 * @license http://www.gnu.org/licenses/gpl-3.0.txt GNU Public License v3
 * @copyright http://www.mijndomein.nl/
 * @version 0.5
 * @link http://php5-sidnepp.svn.sourceforge.net/viewvc/php5-sidnepp/trunk/dev/docs/index.html
 * @see http://php5-sidnepp.svn.sourceforge.net/viewvc/php5-sidnepp/trunk/dev/docs/php5-sidnepp/EppProtocol.html
 * @package php5-sidnepp

  */
class EppProtocol
{
	/**
	 *
	 * @var resource
	 */
	protected $connection;
	/**
	 *
	 * @var timeout
	 */
	protected $timeout;

	function __construct()
	{

	}
	/**
	 * Disconnects if connected
	 * @return boolean
	 */
	function disconnect()
	{
		if (is_resource($this->connection))
		{
			fclose($this->connection);
		}
		return true;
	}
	/**
	 * Connect to the address and port
	 * @param string $address
	 * @param int $port
	 * @param int $timeout
	 * @return boolean
	 */
	function connect($address, $port, $timeout)
	{
		//We don't want our error handler to kick in at this point...
		putenv('SURPRESS_ERROR_HANDLER=1');
		$this->connection = fsockopen($address, $port, $errno, $errstr, $timeout);
		putenv('SURPRESS_ERROR_HANDLER=0');
		if (is_resource($this->connection))
		{
			stream_set_blocking($this->connection, false);
			$this->timeout = $timeout;			
			if ($errno == 0)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}
	/**
	 * This will read 1 response from the connection
	 * @return string
	 */
	function read()
	{
		$content = '';
		$time = time()+$this->timeout;
		$connections[] = $this->connection;
		while (! isset ($length) || $length > 0)
		{
			if (feof($this->connection))
			{
				throw new Exception ('Unexpected closed connection by remote host...');
			}
			//Check if timeout occured
			if (time() >= $time)
			{
				return false;
			}
			//If we dont know how much to read we read the first few bytes first, these contain the content-lenght
			//of whats to come
			if ( !isset($length) || $length == 0)
			{
				if ($read = fread($this->connection, 4))
				{
					$length = $this->readInteger($read)-4;
				}
			}
			//We know the length of what to read, so lets read the stuff
			if ( isset($length) && $length > 0)
			{
				$time = time()+5;
				if ($read = fread($this->connection, 1024))
				{
					$length = $length-strlen($read);
					$content .= $read;
				}
			}
		}
		//echo "read:\n";
		//print_r($content);
		return $content;
	}

	/**
	 * This parses the first 4 bytes into an integer for use to compare content-length
	 *
	 * @param string $content
	 * @return integer
	 */
	function readInteger($content)
	{
		$int = substr($content, 0, 4);
		$int = ord($int[3])+256*(ord($int[2])+256*(ord($int[1])+256*(ord($int[0]))));
		return $int;
	}

	/**
	 * This adds the content-length to the content that is about to be written over the EPP Protocol
	 *
	 * @param string $content Your XML
	 * @return string String to write
	 */
	function addInteger($content)
	{
		$len  = strlen($content)+4;
		$int3 = chr($len%256);
		$len  = $len/256;
		$int2 = chr($len%256);
		$len  = $len/256;
		$int1 = chr($len%256);
		$len  = $len/256;
		$int0 = chr($len%256);
		$int  = array ($int0, $int1, $int2, $int3);
		$int  = implode('', $int);
		//echo "int is $int0 en $int1 en $int2 en $int3\n";

		#echo (strlen($content)+4)." ".$this->readInteger($int)."\n";
		return $int.$content;
	}
	/**
	 * Write stuff over the EPP connection
	 * @param string $content
	 * @return boolean
	 */
	function write($content)
	{
		//echo "start write\n";
		//print_r($content);
		$content = $this->addInteger($content);

		if (!is_resource($this->connection))
		{
			throw new Exception ('Writing while no connection is made is not supported.');
		}
		//echo "de content is:\n" . $content . "\n";
		if (fputs($this->connection, $content, strlen($content)))
		{
			#echo "\n---- WRITE ----\n";
			#echo $content."";
			#echo "\n---- READ ----\n";
			return true;
		}
		return false;
	}
}
